package com.nibian.nibian.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.nibian.nibian.R;

import java.util.UUID;

import no.nordicsemi.android.log.ILogSession;
import no.nordicsemi.android.log.LocalLogSession;
import no.nordicsemi.android.log.Logger;


public class MainActivity extends AppCompatActivity implements ScannerFragment.OnDeviceSelectedListener {


    private TextView mDeviceTep;
    private TextView mTextViewDeviceName;

    private EditText mWriteCommand;

    private Button mSend;
    private Button mActionConnect;

    private UARTService.UARTBinder mService;

    private static final int REQUEST_ENABLE_BT = 2;

    private String mDeviceName;

    private static final String TAG = "MainActivity";

    private ILogSession mLogSession;

    private UARTService.UARTBinder mServiceBinder;

    private UARTInterface mUARTInterface;


    private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            final String action = intent.getAction();

            switch (action) {
                case UARTService.BROADCAST_UART_RX: {
                    final String extra_data = intent.getStringExtra(UARTService.EXTRA_DATA);
                    showExtraDate(extra_data);
                    break;
                }
                case BleProfileService.BROADCAST_CONNECTION_STATE: {
                    final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED);

                    switch (state) {
                        case BleProfileService.STATE_CONNECTED: {
                            mDeviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME);
                            onDeviceConnected();
                            break;
                        }
                        case BleProfileService.STATE_DISCONNECTED: {
                            onDeviceDisconnected();
                            mDeviceName = null;
                            break;
                        }
                        case BleProfileService.STATE_LINK_LOSS: {
                            //                            onLinklossOccur();
                            break;
                        }
                        case BleProfileService.STATE_CONNECTING:
                        case BleProfileService.STATE_DISCONNECTING:
                            // current implementation does nothing in this states
                        default:
                            // there should be no other actions
                            break;
                    }
                    break;
                }
                case BleProfileService.BROADCAST_SERVICES_DISCOVERED: {
//                    final boolean primaryService = intent.getBooleanExtra(BleProfileService.EXTRA_SERVICE_PRIMARY, false);
//                    final boolean secondaryService = intent.getBooleanExtra(BleProfileService.EXTRA_SERVICE_SECONDARY, false);
//
//                    if (primaryService) {
//                        onServicesDiscovered(secondaryService);
//                    } else {
//                        onDeviceNotSupported();
//                    }
                    Log.e(TAG,"BleProfileService.BROADCAST_SERVICES_DISCOVERED");
                    break;
                }
                case BleProfileService.BROADCAST_DEVICE_READY: {
//                    onDeviceReady();
                    Log.e(TAG,"BleProfileService.BROADCAST_DEVICE_READY");
                    break;
                }
                case BleProfileService.BROADCAST_BOND_STATE: {
                    final int state = intent.getIntExtra(BleProfileService.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
                    switch (state) {
                        case BluetoothDevice.BOND_BONDING:
//                            onBondingRequired();
                            Log.e(TAG,"BleProfileService.BOND_BONDING");
                            break;
                        case BluetoothDevice.BOND_BONDED:
                            Log.e(TAG,"BleProfileService.BOND_BONDED");
                            //                            onBonded();
                            break;
                    }
                    break;
                }
                case BleProfileService.BROADCAST_BATTERY_LEVEL: {
//                    final int value = intent.getIntExtra(BleProfileService.EXTRA_BATTERY_LEVEL, -1);
//                    if (value > 0)
//                        onBatteryValueReceived(value);
                    Log.e(TAG,"BleProfileService.BROADCAST_BATTERY_LEVEL");
                    break;
                }
                case BleProfileService.BROADCAST_ERROR: {
                    final String message = intent.getStringExtra(BleProfileService.EXTRA_ERROR_MESSAGE);
                    final int errorCode = intent.getIntExtra(BleProfileService.EXTRA_ERROR_CODE, 0);
                    onError(message, errorCode);
                    break;
                }
            }
        }
    };

    private void showExtraDate(String extra_data) {
        mDeviceTep.setText(extra_data);
    }

    public void onDeviceDisconnected() {
        mActionConnect.setText(R.string.action_connect);
        mTextViewDeviceName.setText(getDefaultDeviceName());
        //        if (mBatteryLevelView != null)
        //            mBatteryLevelView.setText(R.string.not_available);
        mWriteCommand.setEnabled(false);
        mSend.setEnabled(false);
        try {
            Logger.d(mLogSession, "Unbinding from the service...");
            unbindService(mServiceConnection);
            mService = null;

            Logger.d(mLogSession, "Activity unbinded from the service");
            onServiceUnbinded();
            mDeviceName = null;
            mLogSession = null;
        } catch (final IllegalArgumentException e) {
            // do nothing. This should never happen but does...
        }
    }

    public void onError(final String message, final int errorCode) {
        DebugLogger.e(TAG, "Error occurred: " + message + ",  error code: " + errorCode);
        showToast(message + "(" + errorCode + ")");
    }

    protected void showToast(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
            }
        });
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @SuppressWarnings("unchecked")
        @Override
        public void onServiceConnected(final ComponentName name, final IBinder service) {
            final UARTService.UARTBinder bleService = mService = (UARTService.UARTBinder) service;
            mLogSession = mService.getLogSession();
            mUARTInterface = bleService;
            Logger.d(mLogSession, "Activity binded to the service");
            onServiceBinded(bleService);

            // update UI
            mDeviceName = bleService.getDeviceName();
            mTextViewDeviceName.setText(mDeviceName);
            mActionConnect.setText(R.string.action_disconnect);

            // and notify user if device is connected
            if (bleService.isConnected())
                onDeviceConnected();
        }

        @Override
        public void onServiceDisconnected(final ComponentName name) {
            Logger.d(mLogSession, "Activity disconnected from the service");
            mTextViewDeviceName.setText(getDefaultDeviceName());
            mActionConnect.setText(R.string.action_connect);
            mUARTInterface = null;
            mService = null;
            mDeviceName = null;
            mLogSession = null;
            onServiceUnbinded();
        }
    };

    protected void onServiceBinded(final UARTService.UARTBinder binder) {
        mServiceBinder = binder;
    }
    protected void onServiceUnbinded() {
        mServiceBinder = null;
    }
    protected int getDefaultDeviceName() {
        return R.string.uart_default_name;
    }

    public void onDeviceConnected() {
        mTextViewDeviceName.setText(mDeviceName);
        mActionConnect.setText(R.string.action_disconnect);
        mActionConnect.setEnabled(true);
        mWriteCommand.setEnabled(true);
        mSend.setEnabled(true);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mains);
        ensureBLESupported();
        if (!isBLEEnabled()) {
            showBLEDialog();
        }
        initView();
        LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter());
    }
    private static IntentFilter makeIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE);
        intentFilter.addAction(BleProfileService.BROADCAST_SERVICES_DISCOVERED);
        intentFilter.addAction(BleProfileService.BROADCAST_DEVICE_READY);
        intentFilter.addAction(BleProfileService.BROADCAST_BOND_STATE);
        intentFilter.addAction(BleProfileService.BROADCAST_BATTERY_LEVEL);
        intentFilter.addAction(BleProfileService.BROADCAST_ERROR);
        intentFilter.addAction(UARTService.BROADCAST_UART_RX);
        return intentFilter;
    }

    private void ensureBLESupported() {
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show();
            finish();
        }
    }

    protected boolean isBLEEnabled() {
        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        final BluetoothAdapter adapter = bluetoothManager.getAdapter();
        return adapter != null && adapter.isEnabled();
    }

    protected void showBLEDialog() {
        final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
    }

    private void initView() {

        mSend = (Button) findViewById(R.id.send);
        mActionConnect = (Button) findViewById(R.id.action_connect);

        mWriteCommand = (EditText) findViewById(R.id.write_command);

        mDeviceTep = (TextView) findViewById(R.id.device_tep);
        mTextViewDeviceName = (TextView) findViewById(R.id.device_name);
    }

    public void onConnectClicked(final View view) {
        if (isBLEEnabled()) {
            if (mService == null) {
                showDeviceScanningDialog(null);
            } else {
                mService.disconnect();
            }
        } else {
            showBLEDialog();
        }
    }

    /**
     * 发送的点击事件
     * @param view
     */
    public void onSendMessage(final View view) {
        final String text = mWriteCommand.getText().toString();
        mUARTInterface.send(text);                                  //发送按钮的数据f
        mWriteCommand.setText(null);
        mWriteCommand.requestFocus();
    }


    private void showDeviceScanningDialog(final UUID filter) {
        final ScannerFragment dialog = ScannerFragment.getInstance(filter);
        dialog.show(getSupportFragmentManager(), "scan_fragment");
    }

    @Override
    public void onDeviceSelected(BluetoothDevice device, String name) {

        final int titleId = getLoggerProfileTitle();
        if (titleId > 0) {
            mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name);
            // If nRF Logger is not installed we may want to use local logger
            if (mLogSession == null && getLocalAuthorityLogger() != null) {
                mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
            }
        }

        mDeviceName = name;
        mTextViewDeviceName.setText(name != null ? name : getString(R.string.not_available));
        mActionConnect.setText(R.string.action_connecting);
        mActionConnect.setEnabled(false);

        // The device may not be in the range but the service will try to connect to it if it reach it
        Logger.d(mLogSession, "Creating service...");
        final Intent service = new Intent(this, getServiceClass());
        service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
        if (mLogSession != null)
            service.putExtra(BleProfileService.EXTRA_LOG_URI, mLogSession.getSessionUri());
        startService(service);
        Logger.d(mLogSession, "Binding to the service...");
        bindService(service, mServiceConnection, 0);
    }

    protected int getLoggerProfileTitle() {
        return 0;
    }

    protected Uri getLocalAuthorityLogger() {
        return null;
    }
    protected Class<? extends BleProfileService> getServiceClass() {
        return UARTService.class;
    }

    @Override
    public void onDialogCanceled() {

    }

    @Override
    protected void onStop() {
        super.onStop();

        try {
            // We don't want to perform some operations (e.g. disable Battery Level notifications) in the service if we are just rotating the screen.
            // However, when the activity is finishing, we may want to disable some device features to reduce the battery consumption.
            if (mService != null)
                mService.setActivityIsFinishing(isFinishing());

            Logger.d(mLogSession, "Unbinding from the service...");
            unbindService(mServiceConnection);
            mService = null;
            mUARTInterface = null;
            Logger.d(mLogSession, "Activity unbinded from the service");
            onServiceUnbinded();
            mDeviceName = null;
            mLogSession = null;
        } catch (final IllegalArgumentException e) {
            // do nothing, we were not connected to the sensor
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver);
    }
}
